﻿#include "Lunar.h"
#include "EightChar.h"
#include "Foto.h"
#include "Tao.h"
#include "LunarYear.h"
#include "LunarMonth.h"
#include "Solar.h"
#include <map>
#include <string>
#include <ctime>
#include "LunarUtil.h"
#include <iostream>
#include <cmath>

Lunar::Lunar() :_foto(nullptr), _tao(nullptr), _eightChar(nullptr)
{
    JieQiTable = {};
}

Lunar:: ~Lunar()
{
    if (_eightChar) {
        delete _eightChar;
        _eightChar = nullptr;
    }
    if (_foto != nullptr) {
        delete _foto;
        _foto = nullptr;
    }
    if (_tao != nullptr) {
        delete _tao;
        _tao = nullptr;
    }
    if (solar != nullptr)
    {
        delete solar;
        solar = nullptr;
    }
    JieQiTable.clear();
}

const std::vector<std::string> Lunar::JIE_QI = { "冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪" };

const std::vector<std::string> Lunar::JIE_QI_IN_USE = { "DA_XUE", "冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "DONG_ZHI", "XIAO_HAN", "DA_HAN", "LI_CHUN", "YU_SHUI", "JING_ZHE" };


EightChar* Lunar::getEightChar()
{
    if (_eightChar == nullptr)
    {
        _eightChar = new EightChar(this);
    }
    return	_eightChar;
}

Foto* Lunar::getFoto()
{
    if (_foto == nullptr)
    {
        _foto = Foto::FromLunar(this);
    }
    return _foto;
}


Tao* Lunar::getTao()
{
    if (_tao == nullptr)
    {
        _tao = Tao::FromLunar(*this);
    }
    return _tao;
}

Lunar::Lunar(int lunarYear, int lunarMonth, int lunarDay, int hour, int minute, int second) :Lunar()
{
    LunarYear y = LunarYear::FromYear(lunarYear);
    const LunarMonth* m = y.GetMonth(lunarMonth);

    if (m == nullptr) {
        throw std::invalid_argument("wrong lunar year " + std::to_string(lunarYear) +
                                    " month " + std::to_string(lunarMonth));
    }
    // 校验日期有效性
    if (lunarDay < 1) {
        throw std::invalid_argument("lunar day must bigger than 0");
    }

    int days = m->DayCount;

    if (lunarDay > days) {
        throw std::invalid_argument("only " + std::to_string(days) +
                                    " days in lunar year " + std::to_string(lunarYear) +
                                    " month " + std::to_string(lunarMonth));
    }

    Year = lunarYear;
    Month = lunarMonth;
    Day = lunarDay;
    Hour = hour;
    Minute = minute;
    Second = second;
    // 计算公历日期
    Solar noon = Solar::FromJulianDay(m->FirstJulianDay + lunarDay - 1);
    solar = new Solar(Solar::FromYmdHms(noon.Year, noon.Month, noon.Day, hour, minute, second));
    // 年份变化时重新获取农历年
    if (noon.Year != lunarYear) {
        y = LunarYear::FromYear(noon.Year);
    }
    delete m;
    m = nullptr;

    Compute(y);
}


Lunar* Lunar::FromYmdHms(int lunarYear, int lunarMonth, int lunarDay, int hour, int minute, int second)
{
    return  new Lunar(lunarYear, lunarMonth, lunarDay, hour, minute, second);
}


void Lunar::Compute(LunarYear& lunarYear)
{
    ComputeJieQi(lunarYear);
    ComputeYear();
    ComputeMonth();
    ComputeDay();
    ComputeTime();
    ComputeWeek();
}


void Lunar::ComputeJieQi(LunarYear& lunarYear)
{
    auto julianDays = lunarYear.JieQiJulianDays;
    for (size_t i = 0, j = JIE_QI_IN_USE.size(); i < j; i++)
    {
        Solar temp = Solar::FromJulianDay(julianDays[i]);
        JieQiTable[JIE_QI_IN_USE[i]] = temp; // 拷贝对象
        //std::cout << "JieQiTable[" << JIE_QI_IN_USE[i] << "] = "
        //	<< (JieQiTable)[JIE_QI_IN_USE[i]].YmdHms() << std::endl;
    }
}

void Lunar::ComputeMonth()
{
    Solar* start = nullptr;
    Solar* end = nullptr;
    std::string ymd = solar->Ymd();    // 假设 Solar 有静态成员
    std::string time_str = solar->YmdHms();
    size_t size = JIE_QI_IN_USE.size();

    // 序号：大雪以前-3，大雪到小寒之间-2，小寒到立春之间-1，立春之后0
    int index = -3;
    for (size_t i = 0; i < size; i += 2)
    {
        end = &(JieQiTable)[JIE_QI_IN_USE[i]];
        std::string symd = start == nullptr ? ymd : start->Ymd();
        if (ymd >= symd && ymd < end->Ymd()) {
            break;
            start = end;
            index++;
        }

        //干偏移值（以立春当天起算）
        auto offset = (((YearGanIndexByLiChun + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        MonthGanIndex = ((index < 0 ? index + 10 : index) + offset) % 10;
        MonthZhiIndex = ((index < 0 ? index + 12 : index) + LunarUtil::BASE_MONTH_ZHI_INDEX) % 12;

        start = nullptr;
        index = -3;
        for (auto i = 0; i < size; i += 2)
        {
            end = &(JieQiTable)[JIE_QI_IN_USE[i]];
            auto stime = start == nullptr ? time_str : start->YmdHms();
            if (time_str >= stime && time_str < end->YmdHms())
            {
                break;
            }
            start = end;
            index++;
        }

        //干偏移值（以立春交接时刻起算）
        offset = (((YearGanIndexExact + (index < 0 ? 1 : 0)) % 5 + 1) * 2) % 10;
        MonthGanIndexExact = ((index < 0 ? index + 10 : index) + offset) % 10;
        MonthZhiIndexExact = ((index < 0 ? index + 12 : index) + LunarUtil::BASE_MONTH_ZHI_INDEX) % 12;
    }
}

void Lunar::ComputeYear()
{
    // 以正月初一开始
    auto offset = Year - 4;
    YearGanIndex = offset % 10;
    YearZhiIndex = offset % 12;

    if (YearGanIndex < 0)
    {
        YearGanIndex += 10;
    }

    if (YearZhiIndex < 0)
    {
        YearZhiIndex += 12;
    }

    // 以立春作为新一年的开始的干支纪年
    auto g = YearGanIndex;
    auto z = YearZhiIndex;

    // 精确的干支纪年，以立春交接时刻为准
    auto gExact = YearGanIndex;
    auto zExact = YearZhiIndex;

    auto solarYear = solar->Year;
    auto solarYmd = solar->Ymd();
    auto solarYmdHms = solar->YmdHms();

    // 获取立春的阳历时刻
    auto liChun = (JieQiTable)["立春"];
    if (liChun.Year != solarYear)
    {
        liChun = (JieQiTable)["LI_CHUN"];
    }
    auto liChunYmd = liChun.Ymd();
    auto liChunYmdHms = liChun.YmdHms();

    // 阳历和阴历年份相同代表正月初一及以后
    if (Year == solarYear)
    {
        // 日期比较逻辑
        if (solarYmd < liChunYmd) {
            g--;
            z--;
        }
        // 时间戳精确比较（推荐方案）
        auto parseTime = [](const std::string& datetime) -> std::time_t {
            std::tm tm = {};
            std::istringstream ss(datetime);
            ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
            if (ss.fail()) {
                // 处理错误：返回-1表示无效时间
                return static_cast<time_t>(-1);
            }
            tm.tm_isdst = -1; // 表示夏令时信息未知，由mktime推断
            return std::mktime(&tm);
        };

        if (parseTime(solarYmdHms) < parseTime(liChunYmdHms)) {
            gExact--;
            zExact--;
        }

    }
    else if (Year < solarYear)
    {
        if (solarYmd >= liChunYmd) {
            g++;
            z++;
        }
        // 时间戳精确比较（推荐方案）
        auto parseTime = [](const std::string& datetime) -> std::time_t {
            std::tm tm = {};
            std::istringstream ss(datetime);
            ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
            if (ss.fail()) {
                // 处理错误：返回-1表示无效时间
                return static_cast<time_t>(-1);
            }
            tm.tm_isdst = -1; // 表示夏令时信息未知，由mktime推断
            return std::mktime(&tm);
        };

        if (parseTime(solarYmdHms) >= parseTime(liChunYmdHms)) {
            gExact++;
            zExact++;
        }
    }

    YearGanIndexByLiChun = (g < 0 ? g + 10 : g) % 10;
    YearZhiIndexByLiChun = (z < 0 ? z + 12 : z) % 12;

    YearGanIndexExact = (gExact < 0 ? gExact + 10 : gExact) % 10;
    YearZhiIndexExact = (zExact < 0 ? zExact + 12 : zExact) % 12;
}

void Lunar::ComputeDay()
{
    Solar noon = Solar::FromYmdHms(solar->Year, solar->Month, solar->Day, 12);
    int offset = (int)noon.JulianDay() - 11;
    DayGanIndex = offset % 10;
    DayZhiIndex = offset % 12;

    auto dayGanExact = DayGanIndex;
    auto dayZhiExact = DayZhiIndex;

    // 八字流派2，晚子时（夜子/子夜）日柱算当天
    DayGanIndexExact2 = dayGanExact;
    DayZhiIndexExact2 = dayZhiExact;

    // 八字流派1，晚子时（夜子/子夜）日柱算明天

    std::ostringstream oss;
    oss << std::setw(2) << std::setfill('0') << Hour << ":"
        << std::setw(2) << std::setfill('0') << Minute;
    auto hm = oss.str();
    if (hm >= "23:00" && hm <= "23:59")
    {
        dayGanExact++;
        if (dayGanExact >= 10)
        {
            dayGanExact -= 10;
        }
        dayZhiExact++;
        if (dayZhiExact >= 12)
        {
            dayZhiExact -= 12;
        }
    }

    DayGanIndexExact = dayGanExact;
    DayZhiIndexExact = dayZhiExact;
}



void Lunar::ComputeTime()
{
    std::ostringstream oss;
    oss << std::setw(2) << std::setfill('0') << Hour << ":"
        << std::setw(2) << std::setfill('0') << Minute;
    auto hm = oss.str();

    TimeZhiIndex = LunarUtil::GetTimeZhiIndex(hm);
    TimeGanIndex = (DayGanIndexExact % 5 * 2 + TimeZhiIndex) % 10;
}

void Lunar::ComputeWeek()
{
    WeekIndex = solar->Week();
}


Lunar::Lunar(Solar* solar) : solar(new Solar(*solar)), Hour(solar->Hour), Minute(solar->Minute), Second(solar->Second), _foto(nullptr), _eightChar(nullptr), _tao(nullptr)
{
    LunarYear ly = LunarYear::FromYear(solar->Year);
    std::vector<LunarMonth> months = ly.Months;
    for (const auto& m : months)  // 范围循环遍历 [1](@ref)
    {
        // 计算阳历日期与农历月初的儒略日差
        Solar firstDay = Solar::FromJulianDay(m.FirstJulianDay);
        int daysDiff = solar->Subtract(firstDay);  // 假设 Subtract 返回天数差

        // 检查是否在当前农历月内
        if (daysDiff >= 0 && daysDiff < m.DayCount)
        {
            Year = m.Year;
            Month = m.Month;
            Day = daysDiff + 1;  // 天数从1开始
            break;
        }
    }
    Compute(ly);
}


std::string Lunar::DayInGanZhiExact2()
{
    return DayGanExact2() + DayZhiExact2();
}


std::string Lunar::DayGanExact2()
{
    return LunarUtil::GAN[DayGanIndexExact2 + 1];
}


std::string Lunar::DayZhiExact2()
{
    return LunarUtil::ZHI[DayZhiIndexExact2 + 1];
}

std::string Lunar::DayInGanZhiExact()
{
    return DayGanExact() + DayZhiExact();
}

std::string Lunar::DayGanExact()
{
    return LunarUtil::GAN[DayGanIndexExact + 1];
}

std::string Lunar::DayZhiExact()
{
    return  LunarUtil::ZHI[DayZhiIndexExact + 1];
}

std::string Lunar::YearInGanZhiExact()
{
    return YearGanExact() + YearZhiExact();
}

std::string Lunar::YearGanExact()
{
    return LunarUtil::GAN[YearGanIndexExact + 1];
}

std::string Lunar::YearZhiExact()
{
    return LunarUtil::ZHI[YearZhiIndexExact + 1];
}
std::string Lunar::MonthInGanZhiExact()
{
    return MonthGanExact() + MonthZhiExact();
}

std::string Lunar::MonthGanExact()
{
    return LunarUtil::GAN[MonthGanIndexExact + 1];
}

std::string Lunar::MonthZhiExact()
{
    return LunarUtil::ZHI[MonthZhiIndexExact + 1];
}

std::string Lunar::TimeInGanZhi()
{
    return TimeGan() + TimeZhi();
}

std::string Lunar::TimeGan()
{
    return  LunarUtil::GAN[TimeGanIndex + 1];
}

std::string Lunar::TimeZhi()
{
    return LunarUtil::ZHI[TimeZhiIndex + 1];
}


std::vector<std::string>Lunar::DayYi()
{
    return 	GetDayYi();
}


std::vector<std::string> Lunar::GetDayYi(int sect)
{
    return LunarUtil::GetDayYi(sect == 2 ? MonthInGanZhiExact() : MonthInGanZhi(), DayInGanZhi());
}

std::vector<std::string> Lunar::GetDayJi(int sect)
{
    return LunarUtil::GetDayJi(sect == 2 ? MonthInGanZhiExact() : MonthInGanZhi(), DayInGanZhi());
}

std::string Lunar::MonthInGanZhi()
{
    return MonthGan() + MonthZhi();
}

std::string Lunar::DayInGanZhi()
{
    return  DayGan() + DayZhi();
}

std::string  Lunar::MonthGan()
{
    return LunarUtil::GAN[MonthGanIndex + 1];

}

std::string Lunar::MonthZhi()
{
    return LunarUtil::ZHI[MonthZhiIndex + 1];
}

std::string Lunar::DayGan()
{
    return LunarUtil::GAN[DayGanIndex + 1];
}

std::string Lunar::DayZhi()
{
    return LunarUtil::ZHI[DayZhiIndex + 1];
}

std::vector<std::string>Lunar::DayJiShen()
{
    return LunarUtil::GetDayJiShen(Month, DayInGanZhi());
}


std::vector<std::string>Lunar::DayXiongSha()
{
    return LunarUtil::GetDayXiongSha(Month, DayInGanZhi());
}


std::string Lunar::PengZuGan()
{
    return LunarUtil::PENGZU_GAN[DayGanIndex + 1];
}

std::string Lunar::PengZuZhi()
{
    return LunarUtil::PENGZU_ZHI[DayZhiIndex + 1];
}

std::string  Lunar::YearInGanZhi()
{
    return YearGan() + YearZhi();
}

std::string Lunar::YearGan()
{
    return LunarUtil::GAN[YearGanIndex + 1];
}

std::string Lunar::YearZhi()
{
    return 	LunarUtil::ZHI[YearZhiIndex + 1];
}
std::string Lunar::MonthInChinese()
{
    return  (Month < 0 ? "闰" : "") + LunarUtil::MONTH[std::abs(Month)];
}

std::string Lunar::DayInChinese()
{
    return LunarUtil::DAY[Day];
}
